#pragma once

#include "Sol9Types.h"
#include "Sol9Math.h"
#include "Sol9Util.h"

namespace sol9
{
namespace graphics
{

	class color
	{
	public:
		union
		{
			struct
			{
				u8 a, r, g, b;
			};

			u32 argb;
		};

	public:
		// constructors
		color() : argb(0) {}

		color(u32 _a, u32 _r, u32 _g, u32 _b) : a(_a), r(_r), g(_g), b(_b) {}

		color(u32 _argb) : argb(_argb) {}

		// operators
		// color = color
		color& operator=(const color& other)
		{
			argb = other.argb;
			return *this;
		}

		// color + color
		color operator+(const color& other) const
		{
			color out;
			out.a = core::clamp(getAlpha() + other.getAlpha(), 0u, 255u);
			out.r = core::clamp(getRed() + other.getRed(), 0u, 255u);
			out.g = core::clamp(getGreen() + other.getGreen(), 0u, 255u);
			out.b = core::clamp(getBlue() + other.getBlue(), 0u, 255u);
			return out;
		}

		// color += color
		color& operator+=(const color& other)
		{
			a = core::clamp(getAlpha() + other.getAlpha(), 0u, 255u);
			r = core::clamp(getRed() + other.getRed(), 0u, 255u);
			g = core::clamp(getGreen() + other.getGreen(), 0u, 255u);
			b = core::clamp(getBlue() + other.getBlue(), 0u, 255u);
			return *this;
		}

		// color - color
		color operator-(const color& other) const
		{
			color out;
			out.a = core::clamp(getAlpha() - other.getAlpha(), 0u, 255u);
			out.r = core::clamp(getRed() - other.getRed(), 0u, 255u);
			out.g = core::clamp(getGreen() - other.getGreen(), 0u, 255u);
			out.b = core::clamp(getBlue() - other.getBlue(), 0u, 255u);
			return out;
		}

		// color -= color
		color& operator-=(const color& other)
		{
			a = core::clamp(getAlpha() - other.getAlpha(), 0u, 255u);
			r = core::clamp(getRed() - other.getRed(), 0u, 255u);
			g = core::clamp(getGreen() - other.getGreen(), 0u, 255u);
			b = core::clamp(getBlue() - other.getBlue(), 0u, 255u);
			return *this;
		}

		// color == color
		bool operator==(const color& other) const
		{
			return argb == other.argb;
		}

		// color != color
		bool operator!=(const color& other) const
		{
			return argb != other.argb;
		}

		// functions
		void set(u32 _a, u32 _r, u32 _g, u32 _b)
		{
			a = _a;
			r = _r;
			g = _g;
			b = _b;
		}

		void set(u32 _argb)
		{
			argb = _argb;
		}

		void setAlpha(u32 _a)
		{
			a = _a;
		}

		void setRed(u32 _r)
		{
			r = _r;
		}

		void setGreen(u32 _g)
		{
			g = _g;
		}

		void setBlue(u32 _b)
		{
			b = _b;
		}

		u32 getAlpha() const
		{
			return (u32)a;
		}

		u32 getRed() const
		{
			return (u32)r;
		}

		u32 getGreen() const
		{
			return (u32)g;
		}

		u32 getBlue() const
		{
			return (u32)b;
		}

		u32 getAverage() const
		{
			return (getRed() + getGreen() + getBlue()) / 3;
		}

		color getInterpolated(const color& other, f32 d) const
		{
			d = core::saturate(d);
			const f32 inv = 1.0f - d;

			color out;
			out.a = (u32)(getAlpha() * d + other.getAlpha() * inv);
			out.r = (u32)(getRed() * d + other.getRed() * inv);
			out.g = (u32)(getGreen() * d + other.getGreen() * inv);
			out.b = (u32)(getBlue() * d + other.getBlue() * inv);
			return out;
		}
	};

} // namespace graphics
} // namespace sol9